book/[slug]/page.tsx - 书籍章节页
基本信息
| 属性 | 值 |
| 路径 | src/app/book/[slug]/page.tsx |
| 类型 | Next.js 动态路由页面 (Server Component) |
| 功能 | 显示书籍的单个章节内容 |
功能描述
渲染书籍章节的 MDX 内容,提供章节导航、翻译支持和 SEO 优化。支持多语言内容回退(优先显示翻译内容,不存在则回退到英文)。
导入依赖
import { notFound } from "next/navigation";
import Link from "next/link";
import { getChapterBySlug, getAdjacentChapters, getAllChapters } from "@/lib/book/chapters";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { Button } from "@/components/ui/button";
import { MobileTOCButton } from "@/components/book/sidebar";
import type { Metadata } from "next";
import { getTranslations, getLocale } from "next-intl/server";
Props 接口
interface ChapterPageProps {
params: Promise<{ slug: string }>;
}
静态参数生成
generateStaticParams()
在构建时生成所有章节的静态路径。
export async function generateStaticParams() {
return getAllChapters().map((chapter) => ({
slug: chapter.slug,
}));
}
元数据生成
{
title: `${chapter.title} | The Interactive Book of Prompting`,
description: `${chapter.description}. Learn ${chapter.title.toLowerCase()} techniques...`,
keywords: [chapter.title.toLowerCase(), "prompt engineering", ...],
openGraph: {
type: "article",
url: `https://prompts.chat/book/${slug}`
}
}
章节数据结构
interface Chapter {
slug: string;
title: string;
part: string; // 所属部分名称
description?: string;
order: number;
}
翻译处理
翻译键值
| 类型 | 键值格式 |
| 章节标题 | chapters.${slug} |
| 章节描述 | chapterDescriptions.${slug} |
| 部分名称 | parts.${partKey} |
部分名称映射
const partKeys: Record<string, string> = {
"Introduction": "introduction",
"Foundations": "foundations",
"Techniques": "techniques",
"Advanced": "advanced",
"Best Practices": "bestPractices",
"Use Cases": "useCases",
"Conclusion": "conclusion",
};
回退逻辑
const getChapterTitle = () => {
try {
const translated = t(`chapters.${slug}`);
return translated !== `chapters.${slug}` ? translated : chapter.title;
} catch {
return chapter.title;
}
};
内容加载
多语言内容回退
let Content;
try {
if (locale !== "en") {
try {
Content = (await import(`@/content/book/${locale}/${slug}.mdx`)).default;
} catch {
Content = (await import(`@/content/book/${slug}.mdx`)).default;
}
} else {
Content = (await import(`@/content/book/${slug}.mdx`)).default;
}
} catch {
Content = () => <div>{t("chapter.comingSoon")}</div>;
}
加载优先级:
- 当前语言内容 (
{locale}/{slug}.mdx)
- 英文内容 (
{slug}.mdx)
- 即将推出占位符
UI 结构
Article
├── Chapter Header
│ ├── Part Name (small, primary color)
│ ├── Title + MobileTOCButton
│ └── Description (optional)
├── Chapter Content (prose)
│ └── MDX Content
└── Navigation
├── Previous Chapter (if exists)
└── Next Chapter (if exists)
章节导航
相邻章节获取
const { prev, next } = getAdjacentChapters(slug);
导航按钮
| 位置 | 显示内容 |
| Desktop | 完整章节标题(翻译后) |
| Mobile | "上一章" / "下一章" |
<span className="hidden sm:inline">{translatedTitle}</span>
<span className="sm:hidden">{t("chapter.previous")}</span>
翻译键值
| 键值 | 用途 |
book.chapter.notFound | 章节不存在 |
book.chapter.comingSoon | 内容即将推出 |
book.chapter.previous | 上一章(移动端) |
book.chapter.next | 下一章(移动端) |
chapters.${slug} | 章节标题翻译 |
chapterDescriptions.${slug} | 章节描述翻译 |
parts.${key} | 部分名称翻译 |
组件引用
| 组件 | 来源 | 用途 |
MobileTOCButton | @/components/book/sidebar | 移动端目录按钮 |
内容目录结构
src/content/book/
├── en/
│ ├── 00a-preface.mdx
│ ├── 01-understanding-ai-models.mdx
│ └── ...
├── zh/
│ ├── 00a-preface.mdx
│ └── ...
└── ... (other locales)
路由
| 路径 | 说明 |
/book | 书籍首页 |
/book/{slug} | 章节页面(当前) |
工具函数
| 函数 | 来源 | 用途 |
getChapterBySlug | @/lib/book/chapters | 获取章节信息 |
getAdjacentChapters | @/lib/book/chapters | 获取相邻章节 |
getAllChapters | @/lib/book/chapters | 获取所有章节 |